﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace MyOpenFileDialog
{
    class OpenFileDialogViewModel: INotifyPropertyChanged
    {
        private const string BOSS = "我的电脑";
        private const string LAST_USED_DIR_FILE = "OpenFileDialog.inf";
        private TreeNode _selectedNode;//当前选中的节点
        private bool _multiSelect;

        private List<string> _history = new List<string>();
        private int _historyIndex = 0;

        public OpenFileDialogViewModel(string filter, bool multiSelect = false)
        {
            _multiSelect = multiSelect;
            this.InitFilterItems(filter);
            this.InitTreeNodes();
            this.SelectCommand = new DelegateCommand(this.SelectNode);
            this.OpenOrDoubleClickCommand = new DelegateCommand(this.OpenOrDoubleClick);
            this.GotoCommand = new DelegateCommand(this.Goto);
            this.GotoParentCommand = new DelegateCommand(this.GotoParent, this.CanGoParent);
            this.GoAheadCommnad = new DelegateCommand(this.GoAhead, this.CanGoAhead);
            this.GoBackCommand = new DelegateCommand(this.GoBack, this.CanGoBack);
            this.SortByNameCommand = new DelegateCommand(SortByName);
            this.SortByMondifyTimeCommand = new DelegateCommand(SortByMondifyTime);
            this.SortByFileSizeCommand = new DelegateCommand(SortByFileSize);
            this.SelectionChangeCommand = new DelegateCommand(this.SectionChanged);

            var lastSelectedDir = this.ReadLastSelectedDir();
            if (!string.IsNullOrWhiteSpace(lastSelectedDir))
            {
                this.Goto(lastSelectedDir);
                _history.Add(lastSelectedDir);
            }
            else
            {
                this.GotoBoss();
                _history.Add(this.BossNode.PathInfo.Path);
            }
        }

        // 多选或单选文件
        private void SectionChanged(object obj)
        {
            var collection = (System.Collections.IList)obj;
            var temp = collection.Cast<PathInfo>().Where(p => p.Type == PathType.File);
            if (temp.Count() > 0)
            {
                if (_multiSelect)
                {
                    this.SelectedFiles = new List<PathInfo>(temp);
                }
                else
                {
                    this.SelectedFiles = new List<PathInfo> { temp.First() };
                }
            }
            else
            {
                this.SelectedFiles = null;
            }
        }

        #region 排序

        private void SortByFileSize(object obj)
        {
            this.SortTypeOfName = SortType.None;
            this.SortTypeOfMondifyTime = SortType.None;

            if (this.CurrentFilesAndPaths != null)
            {
                var dirs = this.CurrentFilesAndPaths.Where(c => c.Type == PathType.Dir);
                var files = this.CurrentFilesAndPaths.Where(c => c.Type == PathType.File);

                var temp = new List<PathInfo>();

                if (this.SortTypeOfFileSize == SortType.DESC)
                {
                    temp.AddRange(dirs.OrderBy(c => c.Size));
                    temp.AddRange(files.OrderBy(c => c.Size));

                    this.SortTypeOfFileSize = SortType.ASC;
                }
                else
                {
                    temp.AddRange(files.OrderByDescending(c => c.Size));
                    temp.AddRange(dirs.OrderByDescending(c => c.Size));

                    this.SortTypeOfFileSize = SortType.DESC;
                }

                this.CurrentFilesAndPaths = temp;
            }
        }

        private void SortByMondifyTime(object obj)
        {
            this.SortTypeOfFileSize = SortType.None;
            this.SortTypeOfName = SortType.None;

            if (this.CurrentFilesAndPaths != null)
            {
                var dirs = this.CurrentFilesAndPaths.Where(c => c.Type == PathType.Dir);
                var files = this.CurrentFilesAndPaths.Where(c => c.Type == PathType.File);

                var temp = new List<PathInfo>();

                if (this.SortTypeOfMondifyTime == SortType.DESC)
                {
                    temp.AddRange(dirs.OrderBy(c => c.MondifyTime));
                    temp.AddRange(files.OrderBy(c => c.MondifyTime));

                    this.SortTypeOfMondifyTime = SortType.ASC;
                }
                else
                {
                    temp.AddRange(files.OrderByDescending(c => c.MondifyTime));
                    temp.AddRange(dirs.OrderByDescending(c => c.MondifyTime));

                    this.SortTypeOfMondifyTime = SortType.DESC;
                }

                this.CurrentFilesAndPaths = temp;
            }
        }

        private void SortByName(object obj)
        {
            this.SortTypeOfFileSize = SortType.None;
            this.SortTypeOfMondifyTime = SortType.None;

            if (this.CurrentFilesAndPaths != null)
            {
                var dirs = this.CurrentFilesAndPaths.Where(c => c.Type == PathType.Dir);
                var files = this.CurrentFilesAndPaths.Where(c => c.Type == PathType.File);

                var temp = new List<PathInfo>();

                if (this.SortTypeOfName == SortType.DESC)
                {
                    temp.AddRange(dirs.OrderBy(c => c.Name));
                    temp.AddRange(files.OrderBy(c=>c.Name));

                    this.SortTypeOfName = SortType.ASC;
                }
                else
                {
                    temp.AddRange(files.OrderByDescending(c => c.Name));
                    temp.AddRange(dirs.OrderByDescending(c => c.Name));

                    this.SortTypeOfName = SortType.DESC;
                }

                this.CurrentFilesAndPaths = temp;
            }
        }

        #endregion

        #region 转到XXX

        private bool CanGoParent(object obj)
        {
            return _selectedNode != null && _selectedNode.Parent != null;
        }

        private bool CanGoBack(object obj)
        {
            return _history.Count > 1 && _historyIndex != 0;
        }

        private bool CanGoAhead(object obj)
        {
            return _history.Count > 1 && _historyIndex < _history.Count - 1;
        }

        private void GoBack(object obj)
        {
            if (_historyIndex != 0)
            {
                _historyIndex -= 1;
                this.Goto(_history[_historyIndex]);
            }
        }

        private void GoAhead(object obj)
        {
            if (_historyIndex != _history.Count - 1)
            {
                _historyIndex += 1;
                this.Goto(_history[_historyIndex]);
            }
        }

        private void GotoParent(object obj)
        {
            if (_selectedNode.Parent != null)
            {
                _selectedNode.IsExpanded = false;

                if (_selectedNode.Parent.PathInfo.Type == PathType.Boss)
                {
                    this.GotoBoss();
                }
                else
                {
                    this.Goto(_selectedNode.Parent.PathInfo.Path);
                }
            }
        }

        private void GotoBoss()
        {
            this.CurrentFilesAndPaths = this.LoadSpecialFolders();
            this.BossNode.IsSelected = true;
            this.BossNode.IsExpanded = true;
            _selectedNode = this.BossNode;
        }

        private void Goto(object pathObj)
        {
            string path = pathObj as string;
            string realPath = path;
            var specialFolders = this.LoadSpecialFolders(false);
            var specialFolder = specialFolders.FirstOrDefault(s=>path.StartsWith(s.Name));
            if (specialFolder != null)
            {
                realPath = path.Replace(specialFolder.Name, specialFolder.Path);
            }

            if (!string.IsNullOrWhiteSpace(realPath))
            {
                if (File.Exists(realPath))
                {
                    Process.Start(realPath);
                }
                if (Directory.Exists(realPath))
                {
                    var children = this.LoadChildren(realPath, PathType.Dir | PathType.File, this.CurrentFilter.Value);
                    this.CurrentFilesAndPaths = children;

                    this.LocateTreeNode(realPath);
                }
                this.SelectedDir = path;
            }
        }

        private void Add2History(string path)
        {
            if (!_history.Contains(path))
            {
                _history.Add(path);
                _historyIndex = _history.Count - 1;
            }
        }

        #endregion

        // 初始化扩展名过滤列表
        private void InitFilterItems(string filter)
        {
            List<KeyValuePair<string, string>> kvList = new List<KeyValuePair<string, string>>();
            try
            {
                var splitedStr = filter.Split('|');
                for (int i = 0; i < splitedStr.Length - 1; i += 2)
                {
                    KeyValuePair<string, string> kv = new KeyValuePair<string, string>(splitedStr[i], splitedStr[i + 1]);
                    kvList.Add(kv);
                }
                this.FilterItems = kvList;
                this.CurrentFilter = kvList[0];
            }
            catch
            {
                throw new InvalidOperationException("非法的文件过滤字符串");
            }
        }

        // 定位到树中节点并选中
        private void LocateTreeNode(string path)
        {
            var dirvers = Directory.GetLogicalDrives();

            path = path.Trim();
            if (!dirvers.Any(d=>d == path))
            {
                path = path.Trim(Path.DirectorySeparatorChar);
            }
    
            TreeNode parentNode = this.BossNode;
            TreeNode currentNode = null;

            var specialFolders = this.LoadSpecialFolders(false);
            var specialFolder = specialFolders.FirstOrDefault(s => path.StartsWith(s.Path));

            if (specialFolder != null)
            {
                currentNode = parentNode.Chrildren.First(c => c.PathInfo.Path == specialFolder.Path);
            }
            else
            {
                var dirverPath = dirvers.First(d => path.StartsWith(d));
                currentNode = parentNode.Chrildren.First(c => c.PathInfo.Path == dirverPath);
            }
            while (true)
            {
                Locate(currentNode);

                if (currentNode.PathInfo.Path == path)
                {
                    _selectedNode = currentNode;
                    _selectedNode.IsSelected = true;
                    break;
                }
                else
                {
                    var partPath = path.Substring(currentNode.PathInfo.Path.Length).Split(new char[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries).First();
                    currentNode = currentNode.Chrildren.FirstOrDefault(c => c.PathInfo.Path.Split(Path.DirectorySeparatorChar).Last() == partPath);
                    if (currentNode == null)
                    {
                        this.ShowErrorMessage("未找到该路径");
                        break;
                    }
                }
            }
        }

        // 展开其父节点并加载其子节点
        private void Locate(TreeNode node)
        {
            if (node.Parent != null)
            {
                node.Parent.IsExpanded = true;
            }
            if (node.Chrildren.Count == 0)
            {
                IEnumerable<PathInfo> children = null;
                if (node.PathInfo.Type == PathType.Boss)
                {
                    children = this.LoadSpecialFolders();
                }
                else
                {
                    children = this.LoadChildren(node.PathInfo.Path, PathType.Dir);
                }
                if (children != null)
                {
                    foreach (var item in children)
                    {
                        node.Chrildren.Add(new TreeNode { Parent = node, PathInfo = item });
                    }
                }
            }
        }

        // 双击文件夹、文件或点击“打开”按钮
        private void OpenOrDoubleClick(object obj)
        {
            if (this.SelectedFileOrDir != null && this.SelectedFileOrDir.Type == PathType.Dir)
            {
                this.SelectedDir = this.SelectedFileOrDir.Path;
                this.Goto(this.SelectedFileOrDir.Path);
                this.SelectedFiles = null;
            }
            else if (this.SelectedFiles != null)
            {
                this.WriteLastSelectdDir();
                this.AfterOpenFile?.Invoke(null, null);
            }
        }

        #region 记忆上次打开文件位置

        private void WriteLastSelectdDir()
        {
            try
            {
                File.WriteAllText(LAST_USED_DIR_FILE, this._selectedNode.PathInfo.Path);
            }
            catch (Exception) { }
        }

        private string ReadLastSelectedDir()
        {
            string dir = string.Empty;

            try
            {
                dir = File.ReadAllText(LAST_USED_DIR_FILE);
            }
            catch (Exception) { }

            return dir;
        }

        #endregion

        // 选择了一个节点（目录）后加载节点下的目录和文件
        private void SelectNode(object parameter)
        {
            _selectedNode = (TreeNode)parameter;

            if (_selectedNode != null && _selectedNode.PathInfo.Type == PathType.Dir)
            {
                IEnumerable<PathInfo> childrenDirAndFiles = this.LoadChildren(_selectedNode.PathInfo.Path, PathType.Dir | PathType.File, this.CurrentFilter.Value);
                if (childrenDirAndFiles != null)
                {
                    this.CurrentFilesAndPaths = childrenDirAndFiles;

                    if (_selectedNode.Chrildren.Count == 0)
                    {
                        foreach (var item in childrenDirAndFiles)
                        {
                            if (item.Type == PathType.File)
                            {
                                continue;
                            }
                            TreeNode childNode = new TreeNode
                            {
                                Parent = _selectedNode,
                                PathInfo = item
                            };
                            _selectedNode.Chrildren.Add(childNode);
                        }
                    }
                }
                else
                {
                    this.CurrentFilesAndPaths = null;
                }

                this.SelectedDir = _selectedNode.PathInfo.Path;
            }
            else
            {
                this.SelectedDir = BOSS;
                this.CurrentFilesAndPaths = LoadSpecialFolders();
            }

            this.Add2History(_selectedNode.PathInfo.Path);

            this.SortTypeOfFileSize = SortType.None;
            this.SortTypeOfMondifyTime = SortType.None;
            this.SortTypeOfName = SortType.ASC; //默认按名称正序排序
        }

        private List<PathInfo> LoadChildren(string parentPath, PathType pathType, string fileFilter = null)
        {
            List<PathInfo> children = new List<PathInfo>();

            if ((PathType.Dir & pathType) == PathType.Dir)
            {
                string[] dirs = null;
                try
                {
                    dirs = Directory.GetDirectories(parentPath);
                    dirs = dirs.OrderBy(d => d).ToArray();
                }
                catch (UnauthorizedAccessException)
                {
                    this.ShowErrorMessage("该路径没有访问权限");
                    return null;
                }
                catch(IOException ex)
                {
                    this.ShowErrorMessage(ex.Message);
                    return null;
                }
                catch (Exception)
                {
                    this.ShowErrorMessage("访问出错");
                    return null;
                }

                foreach (var dir in dirs)
                {
                    if (Path.GetFileName(dir).StartsWith("$"))
                    {
                        continue;
                    }

                    FileInfo fi = new FileInfo(dir);

                    PathInfo info = new PathInfo();
                    info.Name = Path.GetFileName(dir);
                    info.Path = dir;
                    info.MondifyTime = fi.LastWriteTime;
                    info.Type = PathType.Dir;
                    children.Add(info);
                }
            }

            if ((PathType.File & pathType) == PathType.File)
            {
                string[] files = null;
                try
                {
                    files = Directory.GetFiles(parentPath);
                    files = files.OrderBy(d => d).ToArray();
                }
                catch (UnauthorizedAccessException)
                {
                    this.ShowErrorMessage("该路径没有访问权限");
                    return null;
                }
                catch
                {
                    this.ShowErrorMessage("访问出错");
                    return null;
                }

                foreach (var file in files)
                {
                    if (Path.GetFileName(file).StartsWith("$"))
                    {
                        continue;
                    }

                    if (!IsMathExtension(file, fileFilter))
                    {
                        continue;
                    }

                    FileInfo fi = new FileInfo(file);

                    PathInfo info = new PathInfo();
                    info.Name = Path.GetFileName(file);
                    info.Path = file;
                    info.MondifyTime = fi.LastWriteTime;
                    info.Size = fi.Length;
                    info.Type = PathType.File;
                    children.Add(info);
                }
            }

            return children;
        }

        private void ShowErrorMessage(string message)
        {
            Message = message;
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(3000);
                Message = null;
            });
        }

        private bool IsMathExtension(string file, string fileFilters)
        {
            if (fileFilters != null)
            {
                string[] filters = fileFilters.Split(';');
                foreach (var item in filters)
                {
                    var exp = item.Replace(".", @"\.").Replace("*", @".+") + "$";
                    if (Regex.IsMatch(file, exp, RegexOptions.IgnoreCase))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        #region 初始化操作

        // 初始化树
        private void InitTreeNodes()
        {
            TreeNode desktopNode = new TreeNode
            {
                PathInfo = new PathInfo
                {
                    Name = "桌面",
                    Type = PathType.Dir,
                    Path = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
                },
                Parent = BossNode,
            };
            BossNode.Chrildren.Add(desktopNode);

            TreeNode videosNode = new TreeNode
            {
                PathInfo = new PathInfo
                {
                    Name = "视频",
                    Type = PathType.Dir,
                    Path = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos)
                },
                Parent = BossNode,
            };
            BossNode.Chrildren.Add(videosNode);

            TreeNode picturesNode = new TreeNode
            {
                PathInfo = new PathInfo
                {
                    Name = "图片",
                    Type = PathType.Dir,
                    Path = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
                },
                Parent = BossNode
            };
            BossNode.Chrildren.Add(picturesNode);

            TreeNode documentsNode = new TreeNode
            {
                PathInfo = new PathInfo
                {
                    Name = "文档",
                    Type = PathType.Dir,
                    Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
                },
                Parent = BossNode
            };
            BossNode.Chrildren.Add(documentsNode);

            TreeNode musicNode = new TreeNode
            {
                PathInfo = new PathInfo
                {
                    Name = "音乐",
                    Type = PathType.Dir,
                    Path = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic)
                },
                Parent = BossNode
            };
            BossNode.Chrildren.Add(musicNode);

            var drives = Directory.GetLogicalDrives();

            foreach (var item in drives)
            {
                TreeNode node = new TreeNode();
                node.PathInfo.Name = node.PathInfo.Path = item;
                node.PathInfo.Type = PathType.Dir;
                node.Parent = BossNode;
                this.Trees[0].Chrildren.Add(node);
            }
        }

        // 初始化驱动器和特殊文件夹（我的文档、我的图片、视频等文件夹）
        private List<PathInfo> LoadSpecialFolders(bool containDrivers = true)
        {
            PathInfo desktop = new PathInfo
            {
                Name = "桌面",
                Type = PathType.Dir,
                Path = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
            };
            PathInfo video = new PathInfo
            {
                Name = "视频",
                Type = PathType.Dir,
                Path = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos)
            };
            PathInfo pictures = new PathInfo
            {
                Name = "图片",
                Type = PathType.Dir,
                Path = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
            };
            PathInfo document = new PathInfo
            {
                Name = "文档",
                Type = PathType.Dir,
                Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
            };
            PathInfo music = new PathInfo
            {
                Name = "音乐",
                Type = PathType.Dir,
                Path = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic)
            };

            List<PathInfo> infoList = new List<PathInfo>() { desktop, video, pictures, document, music };

            if (containDrivers)
            {
                var drives = Directory.GetLogicalDrives();

                foreach (var item in drives)
                {
                    PathInfo dirver = new PathInfo
                    {
                        Name = item,
                        Type = PathType.Dir,
                        Path = item
                    };
                    infoList.Add(dirver);
                }
            }

            return infoList;
        }

        #endregion

        #region 属性

        public ObservableCollection<TreeNode> Trees { get; set; } = new ObservableCollection<TreeNode> { new TreeNode { PathInfo = new PathInfo
        {
            Name = BOSS,
            Type = PathType.Boss,
            Path = string.Empty
        }, IsExpanded = true }};

        /// <summary>
        /// 我的电脑节点
        /// </summary>
        public TreeNode BossNode
        {
            get { return Trees[0]; }
        }

        private IEnumerable<PathInfo> _currentFilesAndPaths;

        /// <summary>
        /// 当前显示的文件夹和文件
        /// </summary>
        public IEnumerable<PathInfo> CurrentFilesAndPaths
        {
            get
            {
                return _currentFilesAndPaths;
            }
            set
            {
                _currentFilesAndPaths = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentFilesAndPaths)));
            }
        }

        /// <summary>
        /// 当前选中的文件夹或文件
        /// </summary>
        public PathInfo SelectedFileOrDir { get; set; }

        private List<PathInfo> _selectedFiles;

        /// <summary>
        /// 当前选中的多个文件
        /// </summary>
        public List<PathInfo> SelectedFiles
        {
            get { return _selectedFiles; }
            set
            {
                _selectedFiles = value;

                if (_selectedFiles != null)
                {
                    SelectedFilesStr = string.Join(",", _selectedFiles.Select(f => f.Name));
                }
                else
                {
                    SelectedFilesStr = null;
                }
            }
        }

        private string _selectedFilesStr;

        /// <summary>
        /// 当前选中的文件（下方文本框显示的值）
        /// </summary>
        public string SelectedFilesStr
        {
            get { return _selectedFilesStr; }
            set
            {
                _selectedFilesStr = value;
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedFilesStr)));
            }
        }

        private string _selectedDir;

        /// <summary>
        /// 当前选中的目录(上方导航文本框绑定的值)
        /// </summary>
        public string SelectedDir
        {
            get { return _selectedDir; }
            set
            {
                var specialFolders = this.LoadSpecialFolders(false);
                var specialFolder = specialFolders.FirstOrDefault(s=>value.StartsWith(s.Path));
                if (specialFolder != null)
                {
                    _selectedDir = specialFolder.Name + value.Substring(specialFolder.Path.Length);
                }
                else
                {
                    _selectedDir = value;
                }
  
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedDir)));
            }
        }

        /// <summary>
        /// 文件名扩展过滤
        /// </summary>
        public List<KeyValuePair<string, string>> FilterItems { get; set; }

        public KeyValuePair<string, string> _currentFilter;

        /// <summary>
        /// 当前选择的文件名扩展名过滤器
        /// </summary>
        public KeyValuePair<string, string> CurrentFilter
        {
            get
            {
                return _currentFilter;
            }
            set
            {
                _currentFilter = value;
                if (_selectedNode != null && _selectedNode.PathInfo.Type == PathType.Dir)
                {
                    var children = this.LoadChildren(_selectedNode.PathInfo.Path, PathType.Dir | PathType.File, value.Value);
                    this.CurrentFilesAndPaths = children;

                    this.SortTypeOfName = SortType.ASC;
                    this.SortTypeOfFileSize = SortType.None;
                    this.SortTypeOfMondifyTime = SortType.None;
                }
            }
        }

        private string _message;

        /// <summary>
        /// 错误提示
        /// </summary>
        public string Message
        {
            get { return _message; }
            set
            {
                _message = value;
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Message)));
            }
        }

        private SortType _sortTypeOfName = SortType.None;

        public SortType SortTypeOfName
        {
            get { return _sortTypeOfName; }
            set
            {
                _sortTypeOfName = value;
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SortTypeOfName)));
            }
        }

        private SortType _sortTypeOfMondifyTime = SortType.None;

        public SortType SortTypeOfMondifyTime
        {
            get { return _sortTypeOfMondifyTime; }
            set
            {
                _sortTypeOfMondifyTime = value;
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SortTypeOfMondifyTime)));
            }
        }

        private SortType _sortTypeOfFileSize = SortType.None;

        public SortType SortTypeOfFileSize
        {
            get { return _sortTypeOfFileSize; }
            set
            {
                _sortTypeOfFileSize = value;
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SortTypeOfFileSize)));
            }
        }

        #endregion

        #region 命令

        public DelegateCommand SelectCommand { get; set; }

        public DelegateCommand OpenOrDoubleClickCommand { get; set; }

        public DelegateCommand GotoCommand { get; set; }

        public DelegateCommand GotoParentCommand { get; set; }

        public DelegateCommand GoAheadCommnad { get; set; }

        public DelegateCommand GoBackCommand { get; set; }

        public DelegateCommand SortByNameCommand { get; set; }

        public DelegateCommand SortByMondifyTimeCommand { get; set; }

        public DelegateCommand SortByFileSizeCommand { get; set; }

        public DelegateCommand SelectionChangeCommand { get; set; }

        #endregion

        #region 事件

        public event EventHandler AfterOpenFile;

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }

    #region 实体

    class TreeNode: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public PathInfo PathInfo { get; set; } = new PathInfo();

        public ObservableCollection<TreeNode> Chrildren { get; set; } = new ObservableCollection<TreeNode>();

        public TreeNode Parent{ get; set; }

        private bool _isSelected;

        public bool IsSelected
        {
            get { return _isSelected; }
            set
            {
                _isSelected = value;
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSelected)));
            }
        }

        private bool _isExpanded;

        public bool IsExpanded
        {
            get { return _isExpanded; }
            set
            {
                _isExpanded = value;
                this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsExpanded)));
            }
        }
    }

    class PathInfo
    {
        public string Name { get; set; }

        public string Path { get; set; }

        public DateTime? MondifyTime { get; set; }

        public long? Size { get; set; }

        public PathType Type { get; set; }
    }

    [Flags]
    enum PathType
    {
        File = 1,
        Dir = 2,
        Boss = 4
    }

    enum SortType
    {
        ASC,
        DESC,
        None
    }

    #endregion
}
